// OpentTxl-C Version 11 safe file input/output
// Copyright 2023, James R. Cordy and others

#include <stdlib.h>
#include <stdio.h>

// Posix file modes
#define READ_MODE 0
#define WRITE_MODE 1

// Posix open modes
#define OPEN_CHAR_READ          2
#define OPEN_CHAR_WRITE         4
#define OPEN_CHAR_APPEND        37      /* 1 + 4 + 32 */
#define OPEN_BINARY_READ        8
#define OPEN_BINARY_WRITE       16

// File table
#define tfmaxFiles 25

struct tffileT {
    FILE *file;
    const char *name;
    char mode;
    
};
extern struct tffileT tffiles[tfmaxFiles];
extern int tflookahead;

// Program arguments
extern int    tfargc;
extern char **tfargv;

// Standard streams
#define tfstdin -2
#define tfstdout -1
#define tfstderr 0

// Safe file operations
#define tfargcount tfargc;
#define tffetcharg(arg, dest) tffetcharg (arg, dest) 

#define tffile(stream) (tffiles[stream+2].file)
#define tffilename(stream) (tffiles[stream+2].name)

#define tfopen(openMode, filename, stream) tfopen (openMode, filename, stream)
#define tfclose(stream)  fclose (tffile (stream)), tffile (stream) = NULL, tffilename (stream) = (char *) (NULL)
#define tfseekend(stream) fseek (tffile (stream), 0, SEEK_END)
#define tfflush() {for(int i=1;i<tfmaxFiles;i++) \
        {if(tffiles[i].file!=NULL && tffiles[i].mode==WRITE_MODE) fflush(tffiles[i].file);}}

#define tfread(readItem, itemSize, stream)   fread (readItem, itemSize, 1, tffile (stream))
#define tfwrite(writeItem, itemSize, stream) fwrite (writeItem, itemSize, 1, tffile (stream))

#define tfeof(stream) ((((tflookahead = (getc (tffile(stream)))) != EOF) \
        ? (ungetc (tflookahead, tffile(stream))) : 1), (feof (tffile(stream))))

#define tfgetstring(getItem, stream) if (fgets (getItem, maxStringLength+1, tffile(stream)) == NULL) \
        { (getItem)[0] = '\0'; } else {int i = stringlen(getItem)-1; if ((getItem)[i] == '\n') (getItem)[i] = '\0'; }
#define tfgetlongstring(getItem, stream) if (fgets (getItem, maxLongStringLength+1, tffile(stream)) == NULL) \
        { (getItem)[0] = '\0'; } else {int i = lstringlen(getItem)-1; if ((getItem)[i] == '\n') (getItem)[i] = '\0'; }

#define tfscanf(stream, format, dest) fscanf (tffile(stream), format, dest)

// Support routines 
extern void tfopen (const int openMode, const string fileName, int *stream);
extern void tffetcharg (const int arg, string dest);
extern void tfinitialize (const int argc, char **argv);
extern void tffinalize (void);

#ifndef IO
// Disable unsafe stdio functions
#undef open
#undef close
#undef fopen
#undef fclose
#undef fdopen
#undef fdclose
#undef read
#undef write
#undef fread
#undef fwrite
#undef fseek
#undef ftell
#undef getc
#undef getchar
#undef gets
#undef getw
#undef mktemp
#undef perror
#undef printf
#undef putc
#undef putchar
#undef puts
#undef putw
#endif
